#include <prism/frontend/semantic_analysis/resolve/function.hpp>
//=====================================================================
#include <algorithm>
//=====================================================================
#include <prism/frontend/syntactical_analysis/marshall.hpp>
#include <prism/frontend/semantic_analysis/resolve/type.hpp>

//=====================================================================
// function_matches_function_call_pred
//=====================================================================
prism::resolve::function_matches_function_call_pred::function_matches_function_call_pred( sooty::const_parseme_ptr_ref call_node )
	: call_node(call_node)
{
	ATMA_ASSERT(call_node->id == ID::function_call);
}

bool prism::resolve::function_matches_function_call_pred::operator()( sooty::const_parseme_ptr_ref candidate ) const
{
	if (candidate->id != ID::function) return false;
	if (marshall::function_call::name(call_node)->value.string != marshall::function::name(candidate)->value.string) return false;

	const sooty::parseme_container& call_pl = marshall::function_call::argument_list(call_node)->children;
	const sooty::parseme_container& candidate_pl = marshall::function::parameter_list(candidate)->children;
	
	// immediately rule the function out if the size is different
	if (call_pl.size() != candidate_pl.size()) return false;
	// the size is the same, and the argument list is empty, so we have a match!
	if (call_pl.empty()) return true;
	
	// little-used stl algorithm
	return std::mismatch(call_pl.begin(), call_pl.end(), candidate_pl.begin(), types_match_pred()).first == call_pl.end();
}


//=====================================================================
// function_matches_function_pred
//=====================================================================
prism::resolve::function_matches_function_pred::function_matches_function_pred( sooty::const_parseme_ptr_ref N )
	: N(N)
{
	ATMA_ASSERT(N->id == ID::function);
}

bool prism::resolve::function_matches_function_pred::operator()( sooty::const_parseme_ptr_ref candidate ) const
{
	if (candidate->id != ID::function) return false;
	if (marshall::function_call::name(N)->value.string != marshall::function::name(candidate)->value.string) return false;

	const sooty::parseme_container& call_pl = marshall::function_call::argument_list(N)->children;
	const sooty::parseme_container& candidate_pl = marshall::function::parameter_list(candidate)->children;
	
	// immediately rule the function out if the size is different
	if (call_pl.size() != candidate_pl.size()) return false;
	// the size is the same, and the argument list is empty, so we have a match!
	if (call_pl.empty()) return true;
	
	// little-used stl algorithm
	return std::mismatch(call_pl.begin(), call_pl.end(), candidate_pl.begin(), types_match_pred()).first == call_pl.end();
}

